%{
#include <stdio.h>
#include <string.h>
#include "table.h"
#include "coolinary.h"

static table symboltable;

extern FILE* yyin;

int numparams;
char* params[26];

static table nutritiontable;

void coolinary_init(void) {
	nutritiontable = table_init(10);

	cooltype water = { .name = "TEMPLATE", .type = "water", .nutrition = 35, .quantity = 1, .time = 0 };
	cooltype dairy = { .name = "TEMPLATE", .type = "dairy", .nutrition = 10, .quantity = 1, .time = 0 };
	cooltype vegetable = { .name = "TEMPLATE", .type = "vegetable", .nutrition = 50, .quantity = 1, .time = 0 };
	cooltype fruit = { .name = "TEMPLATE", .type = "fruit", .nutrition = 50, .quantity = 1, .time = 0 };
	cooltype meat = { .name = "TEMPLATE", .type = "meat", .nutrition = 20, .quantity = 1, .time = 0 };
	cooltype liquid = { .name = "TEMPLATE", .type = "liquid", .nutrition = 5, .quantity = 1, .time = 0 };
	cooltype grain = { .name = "TEMPLATE", .type = "grain", .nutrition = 45, .quantity = 1, .time = 0 };

	int varsz = sizeof(cooltype);

	table_insert(nutritiontable,"water",&water,varsz);
	table_insert(nutritiontable,"dairy",&dairy,varsz);
	table_insert(nutritiontable,"vegetable",&vegetable,varsz);
	table_insert(nutritiontable,"fruit",&fruit,varsz);
	table_insert(nutritiontable,"meat",&meat,varsz);
	table_insert(nutritiontable,"liquid",&liquid,varsz);
	table_insert(nutritiontable,"grain",&grain,varsz);

	symboltable = table_init(50);
}

void yyerror(const char *str) { fprintf(stderr,"error: %s\n",str); }
int yywrap() { 
#ifdef DEBUG
	printf(" < ==== S y m b o l   T a b l e ==== > \n");
	table_print(symboltable);
#endif
return 1; 
} 

int main(int argc, char *argv[]) {
  if( argc != 2 ) {
	printf("Usage: coolinary [filename]\n");
	exit(-1);
  }

  coolinary_init();
  yyin = fopen(argv[1], "r");
  if( yyin == NULL ) {
	printf("coolinary: no input files.\n");
	exit(-2);
  }
  yyparse();
  fclose(yyin);
  return(0);
}

%}

%token TOKOBRACE TOKEBRACE TOKOPAREN TOKEPAREN TOKSEMI TOKCOMMA
%token FUNCBOIL FUNCCHOP FUNCBAKE FUNCGRILL FUNCFRY FUNCPRINT
%token NUMBER WORD TYPE STRING
%token OPDOT

%union {
	float number;
	char* text;
};

%type <text> TYPE WORD STRING

%%

program: /* empty */
	| compound_stmt
	;

compound_stmt:
	TOKOBRACE stmt_list TOKEBRACE
	;

stmt_list: /* empty */
        | stmt TOKSEMI stmt_list
        ;

stmt:
	decl_stmt
	|
        op_boil
        |
        op_chop
	|
	op_bake
	| 
	op_grill
	|
	op_fry
	|
	op_print
        ;

decl_stmt: 
	TYPE decl_list 
	{
		int i = 0;
		char* variable_type = strdup($1);
		for(i=0; i<strlen(variable_type); i++) {
			variable_type[i] = tolower(variable_type[i]);
		}
		cooltype* template = (cooltype*)table_retrieve(nutritiontable,variable_type);
#ifdef DEBUG
		printf("Declaring variables of type: %s\n", variable_type ); 
		printf("Nutritional Value: %d\n", template->nutrition);
		printf("Number of declarations: %d\n", numparams);
#endif
		for(i=0; i<numparams; i++) {
			if( table_includes(symboltable,params[i]) == -1 ) {
				table_insert(symboltable,params[i],template,sizeof(cooltype));
			} else {
				yyerror("Compile-Time Error");
				printf("Variable %s already defined.\n", params[i]);
				exit(-1);
			}
		}
		numparams = 0;
	}
	;

decl_list:
	WORD 
	{
		params[numparams++] = strdup($1);
	}
	|
	WORD TOKCOMMA decl_list
	{
		params[numparams++] = strdup($1);
	}
	;

param_list: /* empty */
	| WORD 
	| NUMBER 
	| param_list TOKCOMMA 
	;

op_boil:
        WORD OPDOT FUNCBOIL TOKOPAREN param_list TOKEPAREN
        {
		if( table_includes(symboltable,$1) != -1) {
	                printf("\tBoiling %s!\n", $1);
		} else {
			yyerror("Compile-Time Error");
			printf("Variable %s undefined.\n", $1);
		}
        }
        ;

op_chop:
        WORD OPDOT FUNCCHOP TOKOPAREN param_list TOKEPAREN
        {
		if( table_includes(symboltable,$1) != -1) {
	                printf("\tChopping %s!\n", $1);
		} else {
			yyerror("Compile-Time Error");
			printf("Variable %s undefined.\n", $1);
		}
        }
        ;

op_bake:
        WORD OPDOT FUNCBAKE TOKOPAREN param_list TOKEPAREN
        {
		if( table_includes(symboltable,$1) != -1) {
	                printf("\tBaking %s!\n", $1);
		} else {
			yyerror("Compile-Time Error");
			printf("Variable %s undefined.\n", $1);
		}
        }
        ;

op_grill:
        WORD OPDOT FUNCGRILL TOKOPAREN param_list TOKEPAREN
        {
		if( table_includes(symboltable,$1) != -1) {
	                printf("\tGrilling %s!\n", $1);
		} else {
			yyerror("Compile-Time Error");
			printf("Variable %s undefined.\n", $1);
		}
        }
        ;

op_fry:
        WORD OPDOT FUNCFRY TOKOPAREN param_list TOKEPAREN
        {
		if( table_includes(symboltable,$1) != -1) {
	                printf("\tFrying %s!\n", $1);
		} else {
			yyerror("Compile-Time Error");
			printf("Variable %s undefined.\n", $1);
		}
        }
        ;

op_print:
	FUNCPRINT TOKOPAREN STRING TOKEPAREN
	{
		printf("%s\n",$3);
	};
